package com.shopnight.component;

import com.alibaba.fastjson.JSON;
import com.shopnight.entity.ChatPrivate;
import com.shopnight.entity.User;
import com.shopnight.service.ChatPrivateService;
import com.shopnight.service.UserService;
import com.shopnight.socketVo.OnOpenPrivateVo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;


@ServerEndpoint(value = "/webSocketPrivateChat/{userId}/{otherPeopleId}")
@Component
public class WebSocketPrivateChat {
    private final static Logger logger = LogManager.getLogger(WebSocket.class);
    private static ConcurrentHashMap<Integer, WebSocketPrivateChat> webSocketMap = new ConcurrentHashMap<>();
    private Session session;
    private Integer userId;
    private Integer otherPeopleId;
    private String otherPeopleName;
    private String otherPeopleAvatar;
    private String userNick;
    private String avatar;
    private static Executor executor;
    private static UserService userService;
    private static ChatPrivateService chatPrivateService;

    @Autowired
    public void setUser(UserService userService) {
        WebSocketPrivateChat.userService = userService;
    }

    @Autowired
    public void ThreadPoolExecutor(@Qualifier("taskExecutor") Executor executor) {
        WebSocketPrivateChat.executor = executor;
    }

    @Autowired
    public void setChatPrivateService(ChatPrivateService chatPrivateService) {
        WebSocketPrivateChat.chatPrivateService = chatPrivateService;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId, @PathParam(value = "otherPeopleId") Integer otherPeopleId) {
        this.session = session;
        this.userId = userId;
        this.otherPeopleId = otherPeopleId;
        webSocketMap.put(userId, this);
        webSocketMap.put(otherPeopleId,this);
        User user = userService.getById(userId.longValue());
        User otherPeople = userService.getById(otherPeopleId.longValue());
        this.userNick = user.getUserNick();
        this.avatar = user.getAvatar();
        this.otherPeopleName = otherPeople.getUserNick();
        this.otherPeopleName = otherPeople.getUserNick();
        this.otherPeopleAvatar = otherPeople.getAvatar();
        OnOpenPrivateVo onOpenPrivateVo = new OnOpenPrivateVo();
        onOpenPrivateVo.setUserId(userId);
        onOpenPrivateVo.setUserNick(userNick);
        onOpenPrivateVo.setAvatar(avatar);
        onOpenPrivateVo.setOtherPeopleId(otherPeopleId);
        onOpenPrivateVo.setOtherPeopleName(otherPeopleName);
        onOpenPrivateVo.setOtherPeopleAvatar(otherPeopleAvatar);
            try {
                String jsonString = JSON.toJSONString(onOpenPrivateVo);
                webSocketMap.get(otherPeopleId).sendMessage(jsonString);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    /**
     * 向客户端发送消息
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发生错误时调用
     *
     * @OnError
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("来自客户端用户：{} 消息:{} 传递给用户{}",userId, message,otherPeopleId);
        CompletableFuture<Boolean> booleanCompletableFuture = CompletableFuture.supplyAsync(() -> {
            ChatPrivate chatPrivate = new ChatPrivate();
            chatPrivate.setSelfId(userId);
            chatPrivate.setOtherPeopleId(otherPeopleId);
            chatPrivate.setMessage(message);
            chatPrivate.setSendingTime(new Date());
            return chatPrivateService.save(chatPrivate);
        }, executor);
        CompletableFuture<Void> voidCompletableFuture = booleanCompletableFuture.thenRunAsync(() -> {
                try {
                    webSocketMap.get(otherPeopleId).sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
        });
        CompletableFuture.allOf(booleanCompletableFuture,voidCompletableFuture);
    }
}
